const axios = require('axios');
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const { getConfig } = require('./config-manager');

/**
 * Generate a signature for Alibaba Cloud API requests
 * @param {Object} params - Request parameters
 * @param {string} accessKeySecret - Alibaba Cloud access key secret
 * @returns {string} - The signature
 */
function generateSignature(params, accessKeySecret) {
  // Sort parameters alphabetically
  const sortedParams = Object.keys(params).sort().reduce((result, key) => {
    result[key] = params[key];
    return result;
  }, {});

  // Create canonicalized query string
  const canonicalizedQueryString = Object.entries(sortedParams)
    .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
    .join('&');

  // Create string to sign
  const stringToSign = `POST&${encodeURIComponent('/')}&${encodeURIComponent(canonicalizedQueryString)}`;

  // Calculate HMAC-SHA1 signature
  const hmac = crypto.createHmac('sha1', accessKeySecret + '&');
  hmac.update(stringToSign);
  const signature = hmac.digest('base64');

  return signature;
}

/**
 * Generate common parameters for Alibaba Cloud API requests
 * @returns {Object} - Common parameters
 */
function getCommonParams() {
  const timestamp = new Date().toISOString();

  // 获取当前配置
  const config = getConfig();

  return {
    Format: 'JSON',
    Version: '2023-06-01', // API version for Bailian
    AccessKeyId: config.alibaba_cloud_access_key_id || process.env.ALIBABA_CLOUD_ACCESS_KEY_ID,
    SignatureMethod: 'HMAC-SHA1',
    Timestamp: timestamp,
    SignatureVersion: '1.0',
    SignatureNonce: crypto.randomUUID(),
  };
}

/**
 * Make a request to the Bailian API
 * @param {Object} params - Request parameters
 * @param {Object} [options] - Additional options
 * @param {Object} [options.body] - Request body
 * @returns {Promise<Object>} - API response
 */
async function callBailianAPI(params, options = {}) {
  try {
    const commonParams = getCommonParams();
    const allParams = { ...commonParams, ...params };

    // 获取当前配置中的密钥
    const currentConfig = getConfig();

    // Generate signature
    const signature = generateSignature(
      allParams,
      currentConfig.alibaba_cloud_access_key_secret || process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET
    );

    // Add signature to parameters
    allParams.Signature = signature;

    // 获取当前配置中的端点
    const config = getConfig();
    const apiEndpoint = config.bailian_api_endpoint || process.env.BAILIAN_API_ENDPOINT;

    // 检查是否使用 DashScope 兼容模式
    const isDashScopeCompatible = apiEndpoint.includes('dashscope.aliyuncs.com/compatible-mode');

    // 如果是 DashScope 兼容模式，使用不同的请求方式
    if (isDashScopeCompatible) {
      console.log('Using DashScope compatible mode for API call');

      // DashScope 兼容模式不需要签名参数，直接使用 API Key 认证
      try {
        const headers = {
          'Authorization': `Bearer ${config.alibaba_cloud_access_key_secret ||process.env.DASHSCOPE_API_KEY || 'dummy-api-key'}`,
          'Content-Type': 'application/json'
        };

        // 根据不同的 Action 构造不同的请求路径
        let endpoint = apiEndpoint;
        if (params.Action === 'GenerateText') {
          endpoint = `${apiEndpoint}/completions`;
        } else if (params.Action === 'ChatCompletion') {
          endpoint = `${apiEndpoint}/chat/completions`;
        } else if (params.Action === 'ImageUnderstand') {
          endpoint = `${apiEndpoint}/chat/completions`;
        }

        // 构造请求体
        let requestBody;
        if (params.Action === 'GenerateText') {
          requestBody = {
            model: params.ModelId,
            prompt: params.Prompt,
            max_tokens: params.MaxTokens,
            temperature: params.Temperature
          };
        } else if (params.Action === 'ChatCompletion') {
          requestBody = {
            model: params.ModelId,
            messages: JSON.parse(params.Messages),
            max_tokens: params.MaxTokens,
            temperature: params.Temperature
          };
        } else if (params.Action === 'ImageUnderstand') {
          requestBody = {
            model: params.ModelId,
            messages: options.body.Messages,
            max_tokens: params.MaxTokens,
            temperature: params.Temperature
          };
        }

        console.log('DashScope request:', {
          endpoint,
          headers,
          body: requestBody
        });

        // 发送请求
        const response = await axios.post(endpoint, requestBody, { headers });

        // 将 DashScope 响应转换为百炼格式
        return {
          RequestId: response.data.id || 'unknown',
          Message: 'Success',
          Code: 'Success',
          Data: {
            Content: response.data.choices[0].message?.content || response.data.choices[0].text,
            TokenCount: response.data.usage?.completion_tokens || 0
          }
        };
      } catch (error) {
        console.error('DashScope API Error:', error.response?.data || error.message);
        throw error;
      }
    }

    // 准备请求配置
    const requestConfig = {
      params: allParams,
      headers: {
        'Content-Type': 'application/json',
      },
    };

    // Make API request
    let response;
    if (options.body) {
      // 如果有请求体，使用请求体发送数据
      response = await axios.post(apiEndpoint, options.body, requestConfig);
    } else {
      // 否则使用参数发送数据
      response = await axios.post(apiEndpoint, null, requestConfig);
    }

    return response.data;
  } catch (error) {
    // 打印详细错误信息
    console.error('Bailian API Error:', error.response?.data || error.message);
    if (error.response?.data) {
      console.error('Response data:', JSON.stringify(error.response.data, null, 2));
    }
    if (error.response?.status) {
      console.error('Response status:', error.response.status);
    }
    if (error.response?.headers) {
      console.error('Response headers:', error.response.headers);
    }

    // 构造错误消息
    const errorMessage = error.response?.data?.Message || error.message || 'Failed to call Bailian API';
    throw new Error(errorMessage);
  }
}

/**
 * Generate text completion using Bailian API
 * @param {string} prompt - The prompt text
 * @param {number} maxTokens - Maximum tokens to generate
 * @param {number} temperature - Temperature for sampling
 * @returns {Promise<Object>} - API response
 */
async function generateCompletion(prompt, maxTokens = 1024, temperature = 0.7) {
  // 获取当前配置
  const config = getConfig();

  const params = {
    Action: 'GenerateText',
    ModelId: config.bailian_model_id || process.env.BAILIAN_MODEL_ID,
    Prompt: prompt,
    MaxTokens: maxTokens,
    Temperature: temperature,
  };

  return callBailianAPI(params);
}

/**
 * Generate chat response using Bailian API
 * @param {Array} messages - Array of message objects
 * @param {number} maxTokens - Maximum tokens to generate
 * @param {number} temperature - Temperature for sampling
 * @returns {Promise<Object>} - API response
 */
async function generateChat(messages, maxTokens = 1024, temperature = 0.7) {
  // Format messages for Bailian API
  const formattedMessages = messages.map(msg => ({
    role: msg.role,
    content: msg.content
  }));

  // 获取当前配置
  const config = getConfig();

  const params = {
    Action: 'ChatCompletion',
    ModelId: config.bailian_model_id || process.env.BAILIAN_MODEL_ID,
    Messages: JSON.stringify(formattedMessages),
    MaxTokens: maxTokens,
    Temperature: temperature,
  };

  return callBailianAPI(params);
}

/**
 * Analyze image using Bailian API
 * @param {string} imageBase64 - Base64 encoded image data
 * @param {string} prompt - The prompt text for image analysis
 * @param {number} maxTokens - Maximum tokens to generate
 * @param {number} temperature - Temperature for sampling
 * @returns {Promise<Object>} - API response
 */
async function analyzeImage(imageBase64, prompt, maxTokens = 1024, temperature = 0.7) {
  // Format the message with image - using OpenAI compatible format
  const message = {
    role: 'user',
    content: [
      { type: 'text', text: prompt },
      { type: 'image_url', image_url: { url: `data:image/jpeg;base64,${imageBase64}` } }
    ]
  };

  // 获取当前配置
  const config = getConfig();

  // 准备参数（不包含大型数据）
  const params = {
    Action: 'ImageUnderstand',
    ModelId: config.bailian_model_id || process.env.BAILIAN_MODEL_ID,
    MaxTokens: maxTokens,
    Temperature: temperature,
  };

  // 将消息数据放在请求体中
  const body = {
    Messages: [message]
  };

  // 使用请求体发送数据
  return callBailianAPI(params, { body });
}

/**
 * Read an image file and convert it to base64
 * @param {string} filePath - Path to the image file
 * @returns {Promise<string>} - Base64 encoded image data
 */
async function imageToBase64(filePath) {
  try {
    const data = await fs.promises.readFile(filePath);
    return data.toString('base64');
  } catch (error) {
    console.error('Error reading image file:', error);
    throw new Error(`Failed to read image file: ${error.message}`);
  }
}

module.exports = {
  generateCompletion,
  generateChat,
  analyzeImage,
  imageToBase64
};
